/*
 * Copyright (c) 2019 MediaTek Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <assert.h>
#include <debug.h>
#include <err.h>
#include <kernel/vm.h>
#include <libfdt.h>
#include <platform/addressmap.h>
#include <platform/mboot_expdb.h>
#include <platform/sec_devinfo.h>
#include <set_fdt.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <trace.h>

/*
 * DVFS Layout
 *
 * 11BC10 +---------------------+
 *        | LL volt & freq      |
 * 11BC50 +---------------------+
 *        | LL clk & post div   |
 * 11BCA0 +---------------------+
 *        | L volt & freq       |
 * 11BCE0 +---------------------+
 *        | L clk & post div    |
 * 11BD30 +---------------------+
 *        | CCI volt & freq     |
 * 11BD70 +---------------------+
 *        | CCI clk & post div  |
 * 11CBA0 +---------------------+
 *        | CCI map             |
 *        +---------------------+
 */

/* OPP Table Parameter */
#define NR_FREQ 16
#define ARRAY_COL_SIZE 4
#define NR_CCI_TBL 2

/* Guard Pattern */
#define REPO_GUARD0 0x55aa55aa
#define REPO_GUARD1 0xaa55aa55
#define CSRAM_OFFSET 0x0001bc00
#define CSRAM_BASE (SRAM_BASE_PHY + CSRAM_OFFSET) /* base address */
#define CSRAM_SIZE 0x1400 /* total range (5K bytes) */
#define OFFS_TBL_S 0x0010 /* opp data start offset */
#define OFFS_DATA_S 0x02a0 /* opp data end offset */
#define OFFS_CCI_TBL_S 0x0FA0 /* cci map start offset */
#define REPO_I_DATA_S (OFFS_DATA_S / sizeof(u32))
#define REPO_I_REPO_E (CSRAM_SIZE / sizeof(u32)-1)

enum cpu_level {
    CPU_LEVEL_0, /* FY */
    CPU_LEVEL_1,
    CPU_LEVEL_2,
    CPU_LEVEL_3,
    CPU_LEVEL_4,

    NUM_CPU_LEVEL,
};

enum mt_cpu_dvfs_id {
    MT_CPU_DVFS_LL,
    MT_CPU_DVFS_L,
    MT_CPU_DVFS_CCI,

    NR_MT_CPU_DVFS,
};

static unsigned short fyTbl[NR_FREQ * NR_MT_CPU_DVFS][ARRAY_COL_SIZE] = {
    /* Freq, Vproc, post_div, clk_div */
    { 2000, 96, 1, 1 }, /* LL */
    { 1933, 93, 1, 1 },
    { 1866, 89, 1, 1 },
    { 1800, 85, 1, 1 },
    { 1733, 82, 1, 1 },
    { 1666, 78, 1, 1 },
    { 1548, 71, 1, 1 },
    { 1475, 68, 2, 1 },
    { 1375, 64, 2, 1 },
    { 1275, 60, 2, 1 },
    { 1175, 56, 2, 1 },
    { 1075, 51, 2, 1 },
    {  999, 48, 2, 1 },
    {  925, 45, 2, 1 },
    {  850, 42, 2, 1 },
    {  774, 38, 2, 1 },
    { 2200, 107, 1, 1 }, /* L */
    { 2133, 103, 1, 1 },
    { 2066, 98, 1, 1 },
    { 2000, 94, 1, 1 },
    { 1933, 89, 1, 1 },
    { 1866, 85, 1, 1 },
    { 1800, 80, 1, 1 },
    { 1651, 75, 1, 1 },
    { 1503, 69, 1, 1 },
    { 1414, 64, 2, 1 },
    { 1295, 61, 2, 1 },
    { 1176, 57, 2, 1 },
    { 1087, 53, 2, 1 },
    {  998, 50, 2, 1 },
    {  909, 47, 2, 1 },
    {  850, 44, 2, 1 },
    { 1400, 96, 2, 1 }, /* CCI */
    { 1353, 92, 2, 1 },
    { 1306, 88, 2, 1 },
    { 1260, 84, 2, 1 },
    { 1190, 78, 2, 1 },
    { 1155, 75, 2, 1 },
    { 1120, 71, 2, 1 },
    {  984, 64, 2, 1 },
    {  917, 62, 2, 1 },
    {  827, 58, 2, 1 },
    {  737, 54, 2, 2 },
    {  669, 51, 2, 2 },
    {  579, 47, 2, 2 },
    {  512, 44, 2, 2 },
    {  445, 41, 2, 2 },
    {  400, 38, 2, 2 },
};

static unsigned short SbaTbl[NR_FREQ * NR_MT_CPU_DVFS][ARRAY_COL_SIZE] = {
    /* Freq, Vproc, post_div, clk_div */
    { 2000, 88, 1, 1 },    /* LL */
    { 1933, 84, 1, 1 },
    { 1866, 80, 1, 1 },
    { 1800, 76, 1, 1 },
    { 1733, 72, 1, 1 },
    { 1666, 68, 1, 1 },
    { 1548, 64, 1, 1 },
    { 1475, 59, 2, 1 },
    { 1375, 55, 2, 1 },
    { 1275, 51, 2, 1 },
    { 1175, 47, 2, 1 },
    { 1075, 43, 2, 1 },
    {  999, 40, 2, 1 },
    {  925, 37, 2, 1 },
    {  850, 34, 2, 1 },
    {  774, 32, 2, 1 },
    { 2350, 100, 1, 1 },    /* L */
    { 2287, 95, 1, 1 },
    { 2225, 90, 1, 1 },
    { 2150, 85, 1, 1 },
    { 2066, 80, 1, 1 },
    { 2000, 76, 1, 1 },
    { 1933, 72, 1, 1 },
    { 1866, 68, 1, 1 },
    { 1800, 64, 1, 1 },
    { 1621, 58, 1, 1 },
    { 1473, 53, 2, 1 },
    { 1325, 48, 2, 1 },
    { 1176, 43, 2, 1 },
    { 1057, 39, 2, 1 },
    {  939, 35, 2, 1 },
    {  850, 32, 2, 1 },
    { 1400, 88, 2, 1 },    /* CCI */
    { 1353, 84, 2, 1 },
    { 1306, 80, 2, 1 },
    { 1260, 76, 2, 1 },
    { 1190, 70, 2, 1 },
    { 1155, 67, 2, 1 },
    { 1120, 64, 2, 1 },
    { 1007, 59, 2, 1 },
    {  917, 55, 2, 1 },
    {  827, 51, 2, 1 },
    {  737, 47, 2, 2 },
    {  669, 44, 2, 2 },
    {  579, 40, 2, 2 },
    {  512, 37, 2, 2 },
    {  445, 34, 2, 2 },
    {  400, 32, 2, 2 },
};

static unsigned short ProTbl[NR_FREQ * NR_MT_CPU_DVFS][ARRAY_COL_SIZE] = {
    /* Freq, Vproc, post_div, clk_div */
    { 2000, 88, 1, 1 }, /* LL */
    { 1933, 84, 1, 1 },
    { 1866, 80, 1, 1 },
    { 1800, 76, 1, 1 },
    { 1733, 72, 1, 1 },
    { 1666, 68, 1, 1 },
    { 1548, 64, 1, 1 },
    { 1475, 59, 2, 1 },
    { 1375, 55, 2, 1 },
    { 1275, 51, 2, 1 },
    { 1175, 47, 2, 1 },
    { 1075, 43, 2, 1 },
    {  999, 40, 2, 1 },
    {  925, 37, 2, 1 },
    {  850, 34, 2, 1 },
    {  774, 32, 2, 1 },
    { 2400, 100, 1, 1 }, /* L */
    { 2316, 95, 1, 1 },
    { 2233, 90, 1, 1 },
    { 2150, 85, 1, 1 },
    { 2066, 80, 1, 1 },
    { 2000, 76, 1, 1 },
    { 1933, 72, 1, 1 },
    { 1866, 68, 1, 1 },
    { 1800, 64, 1, 1 },
    { 1621, 58, 1, 1 },
    { 1473, 53, 2, 1 },
    { 1325, 48, 2, 1 },
    { 1176, 43, 2, 1 },
    { 1057, 39, 2, 1 },
    {  939, 35, 2, 1 },
    {  850, 32, 2, 1 },
    { 1400, 88, 2, 1 }, /* CCI */
    { 1353, 84, 2, 1 },
    { 1306, 80, 2, 1 },
    { 1260, 76, 2, 1 },
    { 1190, 70, 2, 1 },
    { 1155, 67, 2, 1 },
    { 1120, 64, 2, 1 },
    { 1007, 59, 2, 1 },
    {  917, 55, 2, 1 },
    {  827, 51, 2, 1 },
    {  737, 47, 2, 2 },
    {  669, 44, 2, 2 },
    {  579, 40, 2, 2 },
    {  512, 37, 2, 2 },
    {  445, 34, 2, 2 },
    {  400, 32, 2, 2 },
};

static unsigned short LiteTbl[NR_FREQ * NR_MT_CPU_DVFS][ARRAY_COL_SIZE] = {
    /* Freq, Vproc, post_div, clk_div */
    { 1800, 96, 1, 1 }, /* LL */
    { 1733, 93, 1, 1 },
    { 1666, 90, 1, 1 },
    { 1548, 83, 1, 1 },
    { 1475, 79, 2, 1 },
    { 1375, 73, 2, 1 },
    { 1275, 68, 2, 1 },
    { 1175, 64, 2, 1 },
    { 1075, 56, 2, 1 },
    { 999, 52, 2, 1 },
    { 925, 47, 2, 1 },
    { 850, 43, 2, 1 },
    { 774, 38, 2, 1 },
    { 774, 38, 2, 1 },
    { 774, 38, 2, 1 },
    { 774, 38, 2, 1 },
    { 2000, 107, 1, 1 }, /* L */
    { 1933, 103, 1, 1 },
    { 1866, 98, 1, 1 },
    { 1800, 93, 1, 1 },
    { 1651, 86, 1, 1 },
    { 1503, 78, 1, 1 },
    { 1414, 74, 2, 1 },
    { 1295, 64, 2, 1 },
    { 1176, 61, 2, 1 },
    { 1087, 57, 2, 1 },
    { 998, 52, 2, 1 },
    { 909, 48, 2, 1 },
    { 850, 44, 2, 1 },
    { 850, 44, 2, 1 },
    { 850, 44, 2, 1 },
    { 850, 44, 2, 1 },
    { 1260, 96, 2, 1 }, /* CCI */
    { 1190, 90, 2, 1 },
    { 1155, 87, 2, 1 },
    { 1120, 83, 2, 1 },
    { 984, 75, 2, 1 },
    { 917, 71, 2, 1 },
    { 827, 64, 2, 1 },
    { 737, 60, 2, 2 },
    { 669, 55, 2, 2 },
    { 579, 50, 2, 2 },
    { 512, 45, 2, 2 },
    { 445, 41, 2, 2 },
    { 400, 38, 2, 2 },
    { 400, 38, 2, 2 },
    { 400, 38, 2, 2 },
    { 400, 38, 2, 2 },
};

static unsigned short p95Tbl[NR_FREQ * NR_MT_CPU_DVFS][ARRAY_COL_SIZE] = {
    /* Freq, Vproc, post_div, clk_div */
    { 2000, 96, 1, 1 },     /* LL */
    { 1933, 93, 1, 1 },
    { 1866, 89, 1, 1 },
    { 1800, 85, 1, 1 },
    { 1733, 82, 1, 1 },
    { 1666, 78, 1, 1 },
    { 1548, 71, 1, 1 },
    { 1475, 68, 2, 1 },
    { 1375, 64, 2, 1 },
    { 1275, 60, 2, 1 },
    { 1175, 56, 2, 1 },
    { 1075, 51, 2, 1 },
    {  999, 48, 2, 1 },
    {  925, 45, 2, 1 },
    {  850, 42, 2, 1 },
    {  774, 38, 2, 1 },
    { 2300, 115, 1, 1 },     /* L */
    { 2133, 103, 1, 1 },
    { 2066,  98, 1, 1 },
    { 2000,  94, 1, 1 },
    { 1933,  89, 1, 1 },
    { 1866,  85, 1, 1 },
    { 1800,  80, 1, 1 },
    { 1651,  75, 1, 1 },
    { 1503,  69, 1, 1 },
    { 1414,  64, 2, 1 },
    { 1295,  61, 2, 1 },
    { 1176,  57, 2, 1 },
    { 1087,  53, 2, 1 },
    {  998,  50, 2, 1 },
    {  909,  47, 2, 1 },
    {  850,  44, 2, 1 },
    { 1400, 96, 2, 1 },       /* CCI */
    { 1353, 92, 2, 1 },
    { 1306, 88, 2, 1 },
    { 1260, 84, 2, 1 },
    { 1190, 78, 2, 1 },
    { 1155, 75, 2, 1 },
    { 1120, 71, 2, 1 },
    {  984, 64, 2, 1 },
    {  917, 62, 2, 1 },
    {  827, 58, 2, 1 },
    {  737, 54, 2, 2 },
    {  669, 51, 2, 2 },
    {  579, 47, 2, 2 },
    {  512, 44, 2, 2 },
    {  445, 41, 2, 2 },
    {  400, 38, 2, 2 },
};

static unsigned char CCI_fyTbl[NR_FREQ * NR_CCI_TBL][NR_FREQ] = {
    /* Normal CCI Map */
    { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 7, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11},
    { 7, 7, 7, 7, 8, 9, 9, 10, 10, 11, 12, 12, 12, 12, 12, 12},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 12, 12, 12, 12},
    { 7, 7, 7, 7, 8, 8, 9, 10, 11, 11, 12, 12, 13, 13, 13, 13},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 14},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 13, 13, 14, 14, 14},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 15, 15},
    /* Perf CCI Map */
    { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 0, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
    { 0, 0, 0, 1, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 1, 1, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5},
    { 0, 0, 0, 1, 1, 2, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 0, 0, 0, 1, 1, 2, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 0, 0, 0, 1, 1, 2, 4, 7, 7, 7, 8, 8, 8, 8, 8, 8},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 10, 10, 10},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 11, 11, 11, 11},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 12, 12, 12},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 11, 12, 12},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 11, 12, 12},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 11, 12, 12},
};

static unsigned char CCI_SbaTbl[NR_FREQ * NR_CCI_TBL][NR_FREQ] = {
    /* Normal CCI Map */
    {4, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    {4, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    {4, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9},
    {6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9},
    {6, 6, 7, 7, 7, 8, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10},
    {4, 7, 7, 7, 7, 8, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10},
    {4, 6, 7, 7, 8, 8, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11},
    {4, 6, 7, 7, 7, 8, 9, 9, 9, 10, 11, 12, 12, 12, 12, 12},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 13, 13, 13, 13},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 13, 13, 13, 13},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 13, 14, 14, 14},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 13, 14, 14, 14},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 13, 14, 14, 15},
    {4, 6, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 13, 14, 14, 15},
    /* Perf CCI Map */
    {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
    {0, 0, 0, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3},
    {0, 0, 0, 0, 0, 1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4},
    {0, 0, 0, 0, 0, 1, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 7, 7, 7, 7, 7},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 7, 7, 7, 7, 7, 7, 7},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 8, 8, 8, 8, 8, 8},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 9, 9, 9, 9, 9},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 10, 10, 10, 10},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 10, 10, 10, 10},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 10, 10, 11, 11},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 10, 10, 12, 12},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 10, 10, 12, 13},
    {0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 10, 10, 12, 13},
};

static unsigned char CCI_ProTbl[NR_FREQ * NR_CCI_TBL][NR_FREQ] = {
    /* Normal CCI Map */
    { 4, 5, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 4, 5, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 4, 5, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9},
    { 6, 5, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9},
    { 6, 7, 7, 7, 7, 8, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10},
    { 4, 7, 7, 7, 7, 8, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10},
    { 4, 5, 7, 7, 8, 8, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11},
    { 4, 5, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 12, 12, 12},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 12, 12, 12, 12},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 12, 13, 13, 13},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 12, 13, 14, 14},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 13, 13, 14, 14},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 12, 14, 14, 15},
    { 4, 5, 7, 7, 7, 8, 8, 8, 9, 10, 11, 12, 12, 13, 14, 15},
    /* Perf CCI Map */
    { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 0, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 0, 0, 0, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2},
    { 0, 0, 0, 0, 0, 1, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 5, 5, 5, 5, 5, 5, 5},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 7, 7, 7, 7, 7},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 7, 7, 7, 7, 7, 7, 7},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 9, 9, 9, 9, 9},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 8, 10, 10, 10, 10},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 8, 10, 10, 10, 10},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 8, 10, 10, 12, 12},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 8, 10, 10, 12, 12},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 8, 10, 10, 12, 12},
    { 0, 0, 0, 0, 0, 1, 1, 2, 4, 6, 7, 8, 10, 10, 12, 12},
};

static unsigned char CCI_LiteTbl[NR_FREQ * NR_CCI_TBL][NR_FREQ] = {
    /* Normal CCI Map */
    { 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
    { 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
    { 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
    { 4, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 4, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 4, 5, 5, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 4, 5, 6, 6, 7, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 4, 5, 5, 6, 7, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 4, 5, 5, 6, 7, 8, 8, 9, 9, 10, 10, 10, 10, 10, 10, 10},
    { 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11},
    { 4, 5, 5, 6, 7, 7, 8, 9, 10, 10, 11, 11, 11, 11, 11, 11},
    { 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 12, 12, 12},
    { 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 12, 12, 12, 12, 12},
    { 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 12, 12, 12, 12, 12},
    { 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 12, 12, 12, 12, 12},
    { 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 12, 12, 12, 12, 12},
    /* Perf CCI Map */
    { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
    { 0, 0, 0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 1, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5},
    { 0, 0, 0, 1, 2, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 7, 7, 7, 7, 7, 7},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 8, 8, 8, 8, 8, 8, 8},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 9, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 8, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 8, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 8, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 8, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 8, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 2, 4, 4, 6, 7, 7, 8, 9, 9, 9, 9, 9},
};

static unsigned char CCI_p95Tbl[NR_FREQ * NR_CCI_TBL][NR_FREQ] = {
    /* Normal CCI Map */
    { 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
    { 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
    { 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10},
    { 7, 7, 7, 7, 8, 8, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11},
    { 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 12, 12, 12, 12, 12, 12},
    { 6, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 12, 12, 12, 12},
    { 6, 7, 7, 7, 8, 8, 9, 10, 11, 11, 12, 12, 13, 13, 13, 13},
    { 6, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 14},
    { 6, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 13, 13, 14, 14, 14},
    { 6, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14, 15},
    { 6, 7, 7, 7, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14, 15, 15},
    /* Perf CCI Map */
    { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    { 0, 0, 0, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
    { 0, 0, 0, 1, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
    { 0, 0, 0, 1, 1, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5},
    { 0, 0, 0, 1, 1, 2, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 0, 0, 0, 1, 1, 2, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7},
    { 0, 0, 0, 1, 1, 2, 4, 7, 7, 7, 8, 8, 8, 8, 8, 8},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 9, 9, 9, 9, 9},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 10, 10, 10},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 11, 11, 11, 11},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 12, 12, 12},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 11, 12, 12},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 11, 12, 12},
    { 0, 0, 0, 1, 1, 2, 4, 5, 7, 7, 9, 10, 10, 11, 12, 12},
};

unsigned short *xrecordTbl[NUM_CPU_LEVEL] = {
    [CPU_LEVEL_0] = &fyTbl[0][0],
    [CPU_LEVEL_1] = &SbaTbl[0][0],
    [CPU_LEVEL_2] = &ProTbl[0][0],
    [CPU_LEVEL_3] = &LiteTbl[0][0],
    [CPU_LEVEL_4] = &p95Tbl[0][0],
};

unsigned char *xrecord_CCI_Tbl[NUM_CPU_LEVEL] = {
    [CPU_LEVEL_0] = &CCI_fyTbl[0][0],
    [CPU_LEVEL_1] = &CCI_SbaTbl[0][0],
    [CPU_LEVEL_2] = &CCI_ProTbl[0][0],
    [CPU_LEVEL_3] = &CCI_LiteTbl[0][0],
    [CPU_LEVEL_4] = &CCI_p95Tbl[0][0],
};

static unsigned short *recordTbl;
static unsigned char *record_CCI_Tbl;
u32 *recordRef_s;
u32 *recordRef;
u8 *record_CCI_Ref;

void target_fdt_opp_table(void *fdt)
{
    const char str1[NR_MT_CPU_DVFS][30] = {"/opp_table0/opp", "/opp_table1/opp", "/opp_table2/opp"};
    char str2[30] = {'\0'};
    char buffer[8] = {'\0'};
    int nodeoffset, i, j, val;
    int table_offset = 0, table_offset_2 = 15;
    uint64_t bkup_value;
    unsigned int lv = CPU_LEVEL_0;
    void *dvfs_base_va = paddr_to_kvaddr(CSRAM_BASE);

    recordRef_s = (u32 *)(dvfs_base_va);
    recordRef = (u32 *)(dvfs_base_va + OFFS_TBL_S);
    record_CCI_Ref = (u8 *)(dvfs_base_va + OFFS_CCI_TBL_S);

    val = (get_devinfo_with_index(7) & 0xFF);
    if ((val == 0x09) || (val == 0x90) || (val == 0x08) || (val == 0x10)
        || (val == 0x06) || (val == 0x60) || (val == 0x04) || (val == 0x20))
        lv = CPU_LEVEL_0;
    else if ((val == 0x07) || (val == 0xE0) || (val == 50) || (val == 0x0A))
        lv = CPU_LEVEL_3;
    recordTbl = xrecordTbl[lv];
    record_CCI_Tbl = xrecord_CCI_Tbl[lv];

    memset(recordRef_s, 0, sizeof(recordRef_s[0]) * REPO_I_REPO_E);

    recordRef_s[0] = REPO_GUARD0;
    recordRef_s[1] = REPO_GUARD1;
    recordRef_s[2] = REPO_GUARD0;
    recordRef_s[3] = REPO_GUARD1;
    recordRef_s[REPO_I_DATA_S] = REPO_GUARD0;
    recordRef_s[REPO_I_REPO_E] = REPO_GUARD1;

    for (i = 0; i < NR_FREQ; i++) {
        // Freq, Vproc, post_div, clk_div
        // LL [31:16] = Vproc, [15:0] = Freq
        recordRef[i] = ((*(recordTbl + (i * ARRAY_COL_SIZE) + 1) & 0xFFF) << 16) |
            (*(recordTbl + (i * ARRAY_COL_SIZE)) & 0xFFFF);
        // LL [31:16] = clk_div, [15:0] = post_div
        recordRef[i + NR_FREQ] = ((*(recordTbl + (i * ARRAY_COL_SIZE) + 3) & 0xFF) << 16) |
            (*(recordTbl + (i * ARRAY_COL_SIZE) + 2) & 0xFF);
        if (NR_MT_CPU_DVFS > 2) {
            // L [31:16] = Vproc, [15:0] = Freq
            recordRef[i + 36] = ((*(recordTbl + ((NR_FREQ * 1) + i) *
                ARRAY_COL_SIZE + 1) & 0xFFF) << 16)
                | (*(recordTbl + ((NR_FREQ * 1) + i) * ARRAY_COL_SIZE) & 0xFFFF);
            // L [31:16] = clk_div, [15:0] = post_div
            recordRef[i + 36 + NR_FREQ] = ((*(recordTbl + ((NR_FREQ * 1) + i) *
                ARRAY_COL_SIZE + 3) & 0xFF) << 16)
                | (*(recordTbl + ((NR_FREQ * 1) + i) * ARRAY_COL_SIZE + 2) &
                0xFF);
            // B/CCI [31:16] = Vproc, [15:0] = Freq
            recordRef[i + 72] = ((*(recordTbl + ((NR_FREQ * 2) + i) *
                ARRAY_COL_SIZE + 1) & 0xFFF) << 16) |
                (*(recordTbl + ((NR_FREQ * 2) + i) * ARRAY_COL_SIZE) & 0xFFFF);
            // B/CCI [31:16] = clk_div, [15:0] = post_div
            recordRef[i + 72 + NR_FREQ] = ((*(recordTbl + ((NR_FREQ * 2) + i) *
                ARRAY_COL_SIZE + 3) & 0xFFF) << 16) |
                (*(recordTbl + ((NR_FREQ * 2) + i) * ARRAY_COL_SIZE + 2) & 0xFF);
        }
        if (NR_MT_CPU_DVFS > 3) {
            // CCI [31:16] = Vproc, [15:0] = Freq
            recordRef[i + 108] = ((*(recordTbl + ((NR_FREQ * 3) + i) *
                ARRAY_COL_SIZE + 1) & 0xFFF) << 16) |
                (*(recordTbl + ((NR_FREQ * 3) + i) * ARRAY_COL_SIZE) & 0xFFFF);
            // CCI [31:16] = clk_div, [15:0] = post_div
            recordRef[i + 108 + NR_FREQ] = ((*(recordTbl + ((NR_FREQ * 3) + i) *
                ARRAY_COL_SIZE + 3) & 0xFF) << 16) |
                (*(recordTbl + ((NR_FREQ * 3) + i) * ARRAY_COL_SIZE + 2) & 0xFF);
        }
    }

    recordRef[i*2] = 0xffffffff;
    recordRef[i*2+36] = 0xffffffff;
    recordRef[i*2+72] = 0xffffffff;
    recordRef[i*2+108] = 0xffffffff;

    memcpy(record_CCI_Ref, record_CCI_Tbl, sizeof(u8) * NR_FREQ * NR_FREQ * NR_CCI_TBL);

    for (j = 0; j < NR_MT_CPU_DVFS; j++) {
        for (i = 0; i < NR_FREQ; i++) {
            sprintf(buffer, "%d", i);
            strcpy(str2, str1[j]);
            strncat(str2, buffer, (sizeof(str2) - strlen(str2) - 1));
            nodeoffset = fdt_path_offset(fdt, str2);
            if (nodeoffset < 0)
                dprintf(CRITICAL, "no %s\n", str2);
            bkup_value = (uint64_t)(recordRef[table_offset_2 - i + table_offset]
                & 0xFFFF) * 1000000;
            fdt_setprop_u64(fdt, nodeoffset, "opp-hz", bkup_value);
            fdt_setprop_u32(fdt, nodeoffset, "opp-microvolt",
                ((recordRef[table_offset_2 - i + table_offset] >> 16) * 625 + 40000) * 10);
        }
        table_offset += 36;
    }
}
SET_FDT_INIT_HOOK(target_fdt_opp_table, target_fdt_opp_table);

static void save_hvfs_data(CALLBACK dev_write)
{
    paddr_t buf;
    unsigned long len;

    buf = (paddr_t)(CSRAM_BASE);
    len = CSRAM_SIZE;

    if (!dev_write((uint64_t)buf, len))
        dprintf(CRITICAL, "hvfs dump fail\n");
}
AEE_EXPDB_INIT_HOOK(SYS_CPUHVFS_RAW, 0x3000, save_hvfs_data);
